﻿using IdentityModel;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Octokit;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Text;
using WorkFlowCore.Common.Authorization.JWT;
using WorkFlowCore.Common.Tracers;
using WorkFlowCore.Common.Utils;
using WorkFlowCore.Plugins;

namespace WorkFlowCore.Authorization.JWT
{
    public class JWTAuthenticationManager
    {
        private readonly JWTAuthenticationOptions authenticationOptions;
        private readonly IMemoryCache memoryCache;
        private IServiceProvider serviceProvider;

        public JWTAuthenticationManager(JWTAuthenticationOptions authenticationOptions, IMemoryCache memoryCache, IServiceProvider serviceProvider)
        {
            this.authenticationOptions = authenticationOptions;
            this.memoryCache = memoryCache;
            this.serviceProvider = serviceProvider;
        }

        private string GenerateToken(AuthorizationUser user, Claim[] claims)
        {
            user = user ?? new AuthorizationUser();
            var key = Encoding.ASCII.GetBytes(authenticationOptions.SecretKey);
            var authTime = DateTime.Now;
            var expiredTime = authTime.AddDays(3);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(
                    new Claim[]
                    {
                        new Claim("user-info", JsonConvert.SerializeObject(user)),
                        new Claim("ismanager",user.IsManager? JWTAuthenticationOptions.ClaimTypesRole_Admin:JWTAuthenticationOptions.ClaimTypesRole_Visitor),
                        new Claim(JwtClaimTypes.Issuer,JWTAuthenticationOptions.JwtClaimTypesIssuer),
                        new Claim(JwtClaimTypes.Audience,JWTAuthenticationOptions.JwtClaimTypesAudience),
                    }
                ),
                Expires = expiredTime,
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)

            };
            if (claims != null)
                tokenDescriptor.Subject.AddClaims(claims);

            var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
            var token = jwtSecurityTokenHandler.CreateToken(tokenDescriptor);
            var tokenString = jwtSecurityTokenHandler.WriteToken(token);
            return tokenString;
        }


        private string DefaultLogin(string uid, string pwd)
        {
            //简单登录
            var localPwd = GetLocalPwd();
            var inputPwd = PwdEncrypt(uid + pwd);
            if (!localPwd.Equals(inputPwd))
            {
                throw new Exception("验证失败");
            }
            return Login(new AuthorizationUser { Id = uid, Name = uid, IsManager = true }, null);
        }

        public string Login(AuthorizationUser user, Claim[] claims)
        {
            var token = GenerateToken(user, claims);
            memoryCache.Set(token, "token", new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(30) });
            memoryCache.Set($"login_{user.Id}", token, new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(30) });
            return token;
        }

        public string Login(string token, string uid)
        {
            if (token == null) return null;
            token = token.Replace("Bearer ", "");
            memoryCache.Set(token, "token", new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(30) });
            memoryCache.Set($"login_{uid}", token, new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(30) });
            return token;
        }

        public void Logout(string uid)
        {
            var token = (string)memoryCache.Get($"login_{uid}");
            if (!string.IsNullOrEmpty(token))
            {
                memoryCache.Remove(token);
            }
        }

        public static string PwdEncrypt(string pwd)
        {
            var newPwd = Encrypt.MD5Encrypt32($"6FD08299-7A99-4176-9EFB-2FA705047B1A{pwd}");
            return newPwd;
        }

        public static string GetLocalPwd()
        {
            var path = Path.Combine(AppContext.BaseDirectory, "Authentication", ".token");
            if (File.Exists(path)) return File.ReadAllText(path, Encoding.UTF8);
            return string.Empty;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public static void InitAuthenticationSee()
        {
            var path = Path.Combine(AppContext.BaseDirectory, "Authentication", ".token");
            if (File.Exists(path)) return;
            var dir = Path.GetDirectoryName(path);
            if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);

            File.WriteAllText(path, PwdEncrypt(JWTAuthenticationOptions.DefaultUid + JWTAuthenticationOptions.DefaultPwd), Encoding.UTF8);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public string GenerateDefaultToken()
        {
            return DefaultLogin(JWTAuthenticationOptions.DefaultUid, JWTAuthenticationOptions.DefaultPwd);
        }


        public bool TokenValid(string token)
        {
            var result = !string.IsNullOrWhiteSpace(token) && !string.IsNullOrEmpty((string)memoryCache.Get(token.Replace("Bearer ", "")));
            return result;
        }

        /// <summary>
        /// 检查自定义认证器
        /// </summary>
        /// <param name="verifyInput"></param>
        /// <param name="verifyPluginId">若指定插件id，则只对该插件进行验证</param>
        /// <returns></returns>
        public VerifyOutput CheckCustomizationVerify(VerifyInput verifyInput, string verifyPluginId = null)
        {
            var pluginManager = serviceProvider.GetRequiredService<PluginManager>();
            var customizationVerifies = new List<ICustomizationVerify>();
            if (string.IsNullOrWhiteSpace(verifyPluginId))
            {
                //获取默认认证
                var customizationVerifyImplements = serviceProvider.GetServices<ICustomizationVerify>();
                if (customizationVerifyImplements != null)
                    customizationVerifies.AddRange(customizationVerifyImplements);
                //获取自定义认证插件的认证
                var customizationVerifyExtensions = pluginManager.ResolveAll<ICustomizationVerifyExtension>();
                if (customizationVerifyExtensions != null)
                    customizationVerifies.AddRange(customizationVerifyExtensions);
            }
            else
            {
                var verifyPlugin = pluginManager.Resolve<ICustomizationVerifyExtension>(verifyPluginId);
                if (verifyPlugin != null)
                    customizationVerifies.Add(verifyPlugin);
            }

            foreach (var _customizationVerify in customizationVerifies)
            {
                using (var verifyActivity = WorkflowActivitySource.Source?.StartActivity($"Verify:{_customizationVerify.GetType().FullName}; appid:{verifyInput?.AppId}"));
                var verify = _customizationVerify.Verify(verifyInput);
                if (verify.IsValid)
                {
                    return verify;
                }
            }
            return new VerifyOutput { IsValid = false };
        }
    }
}
